#include "bitstreamparser.h"
#include "ui_bitstreamparser.h"

#include <QAbstractItemView>
#include <QMessageBox>
#include <QShortcut>
#include <QInputDialog>
#include <QDebug>

BitStreamParser::BitStreamParser(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::BitStreamParser), app(Q_NULLPTR)
{
    naluModel = new BitStreamNALUModel(0);
    ui->setupUi(this);
    ui->tableView->verticalHeader()->hide();
    ui->tableView->setModel(naluModel);
    ui->tableView->setColumnWidth(1, 150);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    connect(ui->browerButton, SIGNAL(clicked(bool)),
            this, SLOT(on_file_open_triggered()));
    connect(ui->filesComboBox, SIGNAL(currentTextChanged(QString)),
            this, SLOT(parse_file(QString)));

    QItemSelectionModel *selectModel;
    selectModel = ui->tableView->selectionModel();
    connect(selectModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
            this, SLOT(onSelectionChanged(QItemSelection)));

    QShortcut *file_open_shortcut = new QShortcut(QKeySequence(tr("Ctrl+o", "File|Open")),this);
    QShortcut *file_exit_shortcut = new QShortcut(QKeySequence(tr("Ctrl+q", "File|Exit")), this);
    file_open_shortcut->setEnabled(true);
    file_exit_shortcut->setEnabled(true);
    connect(file_open_shortcut, SIGNAL(activated()), this, SLOT(on_file_open_triggered()));
    connect(file_exit_shortcut, SIGNAL(activated()), this, SLOT(on_file_exit_triggered()));

    //connect(naluModel, SIGNAL(resize_rows()), ui->tableView, SLOT(resizeRowsToContents()));
    //connect(naluModel, SIGNAL(resize_columns()), ui->tableView, SLOT(resizeColumnsToContents()));
    connect(naluModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
            ui->tableView, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
#if 0
    connect(naluModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
            ui->tableView, SLOT(resizeRowsToContents()));
#endif

    //ui->tableView->verticalHeader()->stretchLastSection();
    //ui->tableView->horizontalHeader()->stretchLastSection();

    //Context menu fo tableView
    tableMenu = new QMenu;
    tableMenu->addAction(ui->actionReset);
    tableMenu->addSeparator();
    tableMenu->addAction(ui->actionGotoFirstNALU);
    tableMenu->addAction(ui->actionGotoLastNALU);
    tableMenu->addAction(ui->actionGotoNALU);
    tableMenu->addSeparator();
    tableMenu->addAction(ui->actionFilterINALU);
    tableMenu->addAction(ui->actionFilterPNALU);
    tableMenu->addAction(ui->actionFilterPpsNALU);
    tableMenu->addAction(ui->actionFilterSpsNALU);
    tableMenu->addAction(ui->actionFilterByType);
    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)),
            this, SLOT(on_table_view_context_menu_request(QPoint)));

    QMessageBox msgBox;
    QString info = "Filter is slow for large file";
    msgBox.setIcon(QMessageBox::Warning);
    msgBox.setText(info);
    msgBox.exec();

}

BitStreamParser::~BitStreamParser()
{
    delete ui;
    if (!fileDialog)
    {
        delete fileDialog;
    }
    app = Q_NULLPTR;
}

void BitStreamParser::parse_file(QString fname)
{
    naluModel->parse_file(fname);
}

void BitStreamParser::onSelectionChanged(QItemSelection cur_selection)
{
    if (cur_selection.isEmpty()) {
        return;
    }
    int row = cur_selection.first().topLeft().row();
    struct naluInfo *nalu;
    nalu = naluModel->naluByIndex(row);
    if(!nalu) {
        return;
    }
    //ui->textBrowser->setTextBackgroundColor(QColor(Qt::black));
    //ui->textBrowser->setTextColor(QColor(Qt::white));
    ui->textBrowser->setText(nalu->info);
}

void BitStreamParser::setApp(QApplication *a) {
    app = a;
}

void BitStreamParser::on_file_open_triggered()
{
    fileDialog = new QFileDialog;
    fileDialog->setFileMode(QFileDialog::ExistingFile);
    fileDialog->setNameFilter(tr("H264 Elementary Streams (*.264 *.h264)"));
    fileDialog->setViewMode(QFileDialog::List);
    fileDialog->setDirectory(QDir::currentPath());
    QStringList fileNames;
     if (fileDialog->exec())
         fileNames = fileDialog->selectedFiles();
    qDebug() << fileNames;
    if(fileNames.isEmpty()) {
        return;
    }
    current_parse_file = fileNames.first();
    ui->filesComboBox->addItem(current_parse_file);
    ui->filesComboBox->setCurrentText(current_parse_file);
}

void BitStreamParser::on_help_about_triggered()
{
    QMessageBox msgBox;
    QString info = "Author: Gao Zhenyan\nEmail: gaozhenyan@aliyun.com\n"
                   "Inspired by: https://github.com/leixiaohua1020/h264_analysis.git";
    msgBox.setText(info);
    msgBox.exec();
}

void BitStreamParser::on_file_exit_triggered()
{
    if(app) {
        app->quit();
    } else {
        exit(0);
    }
}

void BitStreamParser::on_table_view_context_menu_request(QPoint point) {
    tableMenu->exec(mapToGlobal(point));
}

void BitStreamParser::on_actionGotoFirstNALU_triggered()
{
    ui->tableView->scrollToTop();
    ui->tableView->selectRow(0);
}

void BitStreamParser::on_actionGotoLastNALU_triggered()
{
    ui->tableView->scrollToBottom();
    ui->tableView->selectRow(naluModel->rowCount() - 1);
}

void BitStreamParser::on_actionGotoNALU_triggered()
{
    bool ok;
    int item = QInputDialog::getInt(this, tr("Get NALU Seq"), tr("target NALU seq:"),
                                                 1, 1, naluModel->rowCount() + 1, 1, &ok);
    if (ok) {
        QModelIndex index;
        index = naluModel->get_index(item-1, 0);
        ui->tableView->scrollTo(index);
        ui->tableView->selectRow(item - 1);
    }
}

void BitStreamParser::filterByType(int type)
{
    int count = naluModel->rowCount();
    for (int i = 0; i < count; ++i) {
        //qDebug() << ui->tableView->indexAt({i, 2}).data().toString() << " " << i;
        if (naluModel->naluByIndex(i)->type != type) {
            ui->tableView->hideRow(i);
        }
    }
}

void BitStreamParser::on_actionFilterINALU_triggered()
{
    filterByType(NAL_UNIT_TYPE_CODED_SLICE_IDR);
}

void BitStreamParser::on_actionFilterPNALU_triggered()
{
    filterByType(NAL_UNIT_TYPE_CODED_SLICE_NON_IDR);
}

void BitStreamParser::on_actionFilterPpsNALU_triggered()
{

    filterByType(NAL_UNIT_TYPE_PPS);
}

void BitStreamParser::on_actionFilterSpsNALU_triggered()
{

    filterByType(NAL_UNIT_TYPE_SPS);
}

void BitStreamParser::on_actionFilterByType_triggered()
{
    QMap<QString, int> map;
    map.insert("NON_IDR", NAL_UNIT_TYPE_CODED_SLICE_NON_IDR);
    map.insert("DP_A", NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A);
    map.insert("DP_B", NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B);
    map.insert("DP_C", NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C);
    map.insert("IDR", NAL_UNIT_TYPE_CODED_SLICE_IDR);
    map.insert("SEI", NAL_UNIT_TYPE_SEI);
    map.insert("SPS", NAL_UNIT_TYPE_SPS);
    map.insert("PPS", NAL_UNIT_TYPE_PPS);
    map.insert("AUD", NAL_UNIT_TYPE_AUD);
    map.insert("END_OF_SEQUENCE", NAL_UNIT_TYPE_END_OF_SEQUENCE);
    map.insert("END_OF_STREAM", NAL_UNIT_TYPE_END_OF_STREAM);
    map.insert("SPS_EXT", NAL_UNIT_TYPE_SPS_EXT);

    bool ok;
    QStringList items(map.keys());
    QString item = QInputDialog::getItem(this, tr("Select NALU Type"),
                                         tr("NALU type to filter:"), items, 0, false, &ok);
    if (ok && !item.isEmpty()) {
        filterByType(map[item]);
    }
}

void BitStreamParser::on_actionReset_triggered()
{
    int count = naluModel->rowCount();
    for (int i = 0; i < count; ++i) {
        ui->tableView->showRow(i);
    }
}
